package algo.LocalSearch;

import algo.Model.VarInt;
import algo.Model.BasicLocalSearchEntity;
import algo.Common.*;

public class NotOverlap extends BasicLocalSearchEntity implements IConstraint {
	VarInt[] _vars;
	VarInt	_x;
	VarInt	_y;
	int _lx;
	int _ly;
	int	_violations;
	
	public NotOverlap(VarInt x, int lx, VarInt y, int ly){
		super(x.getLocalSolver());
		_x = x;
		_y = y;
		_lx = lx;
		_ly = ly;
		post();
	}
	
	void post(){
		_vars = new VarInt[2];
		_vars[0] = _x;
		_vars[1] = _y;
		getLocalSolver().post(this);
	}
	public BasicLocalSearchEntity[] getDependEntities(){
		// return all entities on which the current entity depends
		//System.out.println("BasicLocalSearchEntity::getDependEntity -> this must be implemented within extended class");
		//assert(false);
		return _vars;
	}
	
	
	public String name(){
		//System.out.println("BasicLocalSearchEntity::name -> this must be implemented within extended class");
		//assert(false);
		return "NotOverlap[" + getID() + "]";
	}
	
	@Override
	public int violations() {
		// TODO Auto-generated method stub
		return _violations;
	}

	@Override
	public VarInt[] getVariables() {
		// TODO Auto-generated method stub
		return _vars;
	}

	@Override
	public int getAssignDelta(VarInt x, int val) {
		// TODO Auto-generated method stub
		int newV = _violations;
		if(x == _x){
			newV = 0;
			if(val <= _y.getValue() && _y.getValue() <= val + _lx)
				newV = Utility.min(val + _lx - _y.getValue(), _ly);
			else if(_y.getValue() <= val && val <= _y.getValue() + _ly)
				newV = Utility.min(_y.getValue() + _ly - val, _lx);			
		}else if(x == _y){
			newV = 0;
			if(_x.getValue() <= val && val <= _x.getValue() + _lx)
				newV = Utility.min(_x.getValue() + _lx - val, _ly);
			else if(val <= _x.getValue() && _x.getValue() <= val + _ly)
				newV = Utility.min(val + _ly - _x.getValue(), _lx);			
		}
		return newV - _violations;
	}

	@Override
	public void propagateInt(VarInt x, int val) {
		//System.out.println("NotOverlap::propagateInt(" + x.name() + "," + val + ")");
		// TODO Auto-generated method stub
		// value of x is already updated
		//_violations = 0;
		if(x == _x || _y == x){
			_violations = 0;
			if(_x.getValue() <= _y.getValue() && _y.getValue() <= _x.getValue() + _lx)
				_violations = Utility.min(_x.getValue() + _lx - _y.getValue(), _ly);
			else if(_y.getValue() <= _x.getValue() && _x.getValue() <= _y.getValue() + _ly)
				_violations = Utility.min(_y.getValue() + _ly - _x.getValue(), _lx);
		}
	}

	@Override
	public void initPropagate() {
		// TODO Auto-generated method stub
		_violations = 0;
		if(_x.getValue() <= _y.getValue() && _y.getValue() <= _x.getValue() + _lx)
			_violations = Utility.min(_x.getValue() + _lx - _y.getValue(), _ly);
		else if(_y.getValue() <= _x.getValue() && _x.getValue() <= _y.getValue() + _ly)
			_violations = Utility.min(_y.getValue() + _ly - _x.getValue(), _lx);
	}

	@Override
	public boolean verify() {
		// TODO Auto-generated method stub
		int V = 0;
		if(_x.getValue() <= _y.getValue() && _y.getValue() <= _x.getValue() + _lx)
			V = Utility.min(_x.getValue() + _lx - _y.getValue(), _ly);
		else if(_y.getValue() <= _x.getValue() && _x.getValue() <= _y.getValue() + _ly)
			V = Utility.min(_y.getValue() + _ly - _x.getValue(), _lx);
		if(V != _violations){
			System.out.println("NotOverlap::verify --> failed, _violations = " + violations() + ", but when recomputing, V = " + V);
		}
		return V == _violations;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		LocalSolver ls = new LocalSolver();
		VarIntLS x = new VarIntLS(ls,1,6);
		VarIntLS y = new VarIntLS(ls,1,6);
		ConstraintSystem S = new ConstraintSystem(ls);
		NotOverlap c = new NotOverlap(x,3,y,2);
		NotEqual c2 = new NotEqual(x,y);
		S.post(c);
		S.post(c2);
		S.close();
		ls.close();
		
		System.out.println("Init, x = " + x.getValue() + " y = " + y.getValue() + " S = " + S.violations());
		
		x.setValuePropagate(3);
		System.out.println("Init, x = " + x.getValue() + " y = " + y.getValue() + " S = " + S.violations());
		
		x.setValuePropagate(2);
		System.out.println("Init, x = " + x.getValue() + " y = " + y.getValue() + " S = " + S.violations());
		
		
	}

}
